package edu.internet2.middleware.assurance.mcb.sub.safenet;

import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.velocity.VelocityContext;
import org.opensaml.xml.util.DatatypeHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import edu.internet2.middleware.assurance.mcb.authn.provider.MCBLoginServlet;
import edu.internet2.middleware.assurance.mcb.authn.provider.MCBSubmodule;
import edu.internet2.middleware.assurance.mcb.authn.provider.MCBUsernamePrincipal;
import edu.internet2.middleware.shibboleth.idp.authn.AuthenticationException;
import edu.internet2.middleware.shibboleth.idp.authn.LoginHandler;

public class SafeNetLoginSubmodule implements MCBSubmodule {

	private final Logger log = LoggerFactory.getLogger(SafeNetLoginSubmodule.class);
	private String beanName = null;
	private String loginPage = null;
	private AuthenticationEngine authEngine = null;
    /** HTTP request parameter containing the user name. */
    private final String usernameAttribute = "j_username";

    /** HTTP request parameter containing the user's password. */
    private final String passwordAttribute = "j_password";


	/**
	 * Display the login form to the end user. Also add any error messages to the Velocity context.
	 * 
	 * @return true if successful
	 */
	public boolean displayLogin(MCBLoginServlet servlet, HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException, LoginException {
		VelocityContext vCtx = new VelocityContext();

		// if the user failed login, we stored the reason in the principal object
		// so pull it out if it exists
		MCBUsernamePrincipal principal = (MCBUsernamePrincipal) request.getSession().getAttribute(LoginHandler.PRINCIPAL_KEY);
		if ((principal != null) && (principal.getFailedLogin() != null)) {
			vCtx.put("loginFailed", principal.getFailedLogin());
			log.debug("Failed count = [{}]", principal.getFailedCount());
		} else {
			vCtx.put("loginFailed", "");
		}
		
		log.debug("Displaying SafeNet login template.");
		servlet.doVelocity(request, response, loginPage, vCtx);
		
		principal.setFailedLogin(null);

		return true;
	}

	/**
	 * Process the actual login credentials of the user. Note that we only look for the username and password, so if
	 * you use PIN numbers, they must be added to the password value on the login page before the submission of the
	 * form.
	 * 
	 * @return true if login was successful
	 */
	public boolean processLogin(MCBLoginServlet servlet, HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException, LoginException {
		
    	MCBUsernamePrincipal principal = (MCBUsernamePrincipal) request.getSession().getAttribute(LoginHandler.PRINCIPAL_KEY);
    	
    	String loginid = DatatypeHelper.safeTrimOrNullString(request.getParameter(usernameAttribute));
    	String password = DatatypeHelper.safeTrimOrNullString(request.getParameter(passwordAttribute));
    	
    	try {
	    	AuthResult result = authEngine.loginUser(loginid, password);
	    	
	    	if (result.isResultStatus() == true) { // auth succeeded
		    	principal.setName(loginid);

		    	request.setAttribute(LoginHandler.PRINCIPAL_KEY, principal);

		    	return true;
	    	} else { // auth failed
	    		principal.setFailedLogin(result.getResultMessage());
	    		return false;
	    	}
	    	
    	} catch (Exception e) {
    		principal.setFailedLogin(e.getMessage());
    		return false;
    	}
	}

	/**
	 * Interface defined method. We have nothing to do in it.
	 */
	public void init() {
		// noop
	}

    /**
     * Set the bean name of this component.
     */
	public void setBeanName(String name) {
		beanName = name;
	}
	/**
	 * Get the bean name of this component.
	 */
	public String getBeanName() {
		return beanName;
	}

	/**
	 * Create an instance of this submodule with the necessary information to authenticate users.
	 * @param serverName The SafeNet/Safeword 2008 server hostname or IP address.
	 * @param serverPort The SafeNet/Safeword 2008 server port.
	 * @param loginPage The Velocity template for the login page.
	 */
	public SafeNetLoginSubmodule(String serverName, String serverPort, String loginPage) {
		this.loginPage = loginPage;
		
		authEngine = new AuthenticationEngine(serverName, serverPort);
		
		log.info("Safenet authentication engine created to server [{}]", serverName);
	}
}
